﻿2026-05-16T09:03:30.1531440Z ##[group]Run pnpm verify:phase-4
2026-05-16T09:03:30.1532138Z [36;1mpnpm verify:phase-4[0m
2026-05-16T09:03:30.1562321Z shell: /usr/bin/bash -e {0}
2026-05-16T09:03:30.1562543Z env:
2026-05-16T09:03:30.1562760Z   PNPM_HOME: /home/runner/setup-pnpm/node_modules/.bin
2026-05-16T09:03:30.1563029Z   SKIP_PHASE_3_CARRYOVER: 1
2026-05-16T09:03:30.1563223Z   SKIP_TRACE_CHECK: 1
2026-05-16T09:03:30.1563402Z ##[endgroup]
2026-05-16T09:03:30.3822340Z 
2026-05-16T09:03:30.3843554Z > rebno@0.0.0 verify:phase-4 /home/runner/work/rebno/rebno
2026-05-16T09:03:30.3862063Z > node scripts/verify-phase-4.mjs
2026-05-16T09:03:30.3872825Z 
2026-05-16T09:03:30.4123844Z 
2026-05-16T09:03:30.4124517Z === Workspace: typecheck ===
2026-05-16T09:03:30.4125210Z >>> pnpm -r typecheck
2026-05-16T09:03:30.6455768Z Scope: 5 of 6 workspace projects
2026-05-16T09:03:30.6497267Z packages/db typecheck$ tsc --noEmit
2026-05-16T09:03:30.6503561Z packages/game-logic typecheck$ tsc --noEmit
2026-05-16T09:03:32.6764474Z packages/game-logic typecheck: Done
2026-05-16T09:03:32.6812430Z packages/protocol typecheck$ tsc --noEmit
2026-05-16T09:03:34.1091079Z packages/db typecheck: Done
2026-05-16T09:03:35.3391119Z packages/protocol typecheck: Done
2026-05-16T09:03:35.3400962Z apps/client typecheck$ tsc --noEmit
2026-05-16T09:03:35.3403872Z apps/server typecheck$ tsc --noEmit
2026-05-16T09:03:44.9708593Z apps/client typecheck: Done
2026-05-16T09:03:45.2015523Z apps/server typecheck: Done
2026-05-16T09:03:45.2110153Z 
2026-05-16T09:03:45.2110874Z === Lint: protocol-sync ===
2026-05-16T09:03:45.2111500Z >>> pnpm lint:protocol-sync
2026-05-16T09:03:45.4411542Z 
2026-05-16T09:03:45.4412765Z > rebno@0.0.0 lint:protocol-sync /home/runner/work/rebno/rebno
2026-05-16T09:03:45.4413550Z > node tools/scripts/lint-protocol-sync.mjs
2026-05-16T09:03:45.4414001Z 
2026-05-16T09:03:45.4692052Z lint-protocol-sync: OK
2026-05-16T09:03:45.4797472Z 
2026-05-16T09:03:45.4798153Z === Lint: game-logic-purity ===
2026-05-16T09:03:45.4798830Z >>> pnpm lint:game-logic-purity
2026-05-16T09:03:45.7082205Z 
2026-05-16T09:03:45.7083120Z > rebno@0.0.0 lint:game-logic-purity /home/runner/work/rebno/rebno
2026-05-16T09:03:45.7084059Z > node tools/scripts/lint-game-logic-purity.mjs
2026-05-16T09:03:45.7084508Z 
2026-05-16T09:03:45.7376139Z lint-game-logic-purity: OK (8 file(s) clean)
2026-05-16T09:03:45.7479671Z 
2026-05-16T09:03:45.7480280Z === Lint: better-auth-schema-sync ===
2026-05-16T09:03:45.7480995Z >>> pnpm lint:better-auth-schema-sync
2026-05-16T09:03:45.9850376Z 
2026-05-16T09:03:45.9851616Z > rebno@0.0.0 lint:better-auth-schema-sync /home/runner/work/rebno/rebno
2026-05-16T09:03:45.9852871Z > node tools/scripts/lint-better-auth-schema-sync.mjs
2026-05-16T09:03:45.9853348Z 
2026-05-16T09:03:47.2334414Z lint-better-auth-schema-sync: OK
2026-05-16T09:03:47.2440606Z 
2026-05-16T09:03:47.2441257Z === Lint: rate-limit-budgets ===
2026-05-16T09:03:47.2442031Z >>> pnpm lint:rate-limit-budgets
2026-05-16T09:03:47.4709251Z 
2026-05-16T09:03:47.4710224Z > rebno@0.0.0 lint:rate-limit-budgets /home/runner/work/rebno/rebno
2026-05-16T09:03:47.4711204Z > node tools/scripts/lint-rate-limit-budgets.mjs
2026-05-16T09:03:47.4711995Z 
2026-05-16T09:03:47.4959757Z lint-rate-limit-budgets: OK (5 D-22 budgets locked)
2026-05-16T09:03:47.5064310Z 
2026-05-16T09:03:47.5064834Z === Lint: no-clipboard-rce ===
2026-05-16T09:03:47.5065487Z >>> pnpm lint:no-clipboard-rce
2026-05-16T09:03:47.7307837Z 
2026-05-16T09:03:47.7308899Z > rebno@0.0.0 lint:no-clipboard-rce /home/runner/work/rebno/rebno
2026-05-16T09:03:47.7309808Z > node tools/scripts/lint-no-clipboard-rce.mjs
2026-05-16T09:03:47.7310248Z 
2026-05-16T09:03:47.7598490Z lint-no-clipboard-rce: OK (22 file(s) clean)
2026-05-16T09:03:47.7705941Z 
2026-05-16T09:03:47.7706498Z === Lint: room-layout ===
2026-05-16T09:03:47.7707144Z >>> pnpm lint:room-layout
2026-05-16T09:03:47.9932172Z 
2026-05-16T09:03:47.9933140Z > rebno@0.0.0 lint:room-layout /home/runner/work/rebno/rebno
2026-05-16T09:03:47.9933962Z > node tools/scripts/lint-room-layout.mjs
2026-05-16T09:03:47.9935024Z 
2026-05-16T09:03:48.0238973Z lint-room-layout: OK
2026-05-16T09:03:48.0341678Z 
2026-05-16T09:03:48.0342674Z === ADR 0004 lint ===
2026-05-16T09:03:48.0343281Z >>> pnpm lint:adr:0004
2026-05-16T09:03:48.2652000Z 
2026-05-16T09:03:48.2653169Z > rebno@0.0.0 lint:adr:0004 /home/runner/work/rebno/rebno
2026-05-16T09:03:48.2654235Z > node tools/asset-catalog/scripts/lint-adr.mjs docs/adr/0004-room-hot-reload.md --no-matrix
2026-05-16T09:03:48.2654921Z 
2026-05-16T09:03:48.2904076Z OK: ADR docs/adr/0004-room-hot-reload.md validated (no-matrix mode — Michael Nygard sections present)
2026-05-16T09:03:48.3005675Z 
2026-05-16T09:03:48.3006273Z === Drizzle: emit-check ===
2026-05-16T09:03:48.3006850Z >>> pnpm db:emit-check
2026-05-16T09:03:48.5268619Z 
2026-05-16T09:03:48.5269580Z > rebno@0.0.0 db:emit-check /home/runner/work/rebno/rebno
2026-05-16T09:03:48.5272015Z > pnpm -C packages/db exec drizzle-kit generate && node -e "require('fs').copyFileSync('packages/db/migrations/0001_baseline.sql','docs/extracted-server/0001_baseline.sql')" && git diff --exit-code packages/db/migrations/0001_baseline.sql docs/extracted-server/0001_baseline.sql
2026-05-16T09:03:48.5273693Z 
2026-05-16T09:03:48.8662919Z No config path provided, using default 'drizzle.config.ts'
2026-05-16T09:03:48.8664169Z Reading config file '/home/runner/work/rebno/rebno/packages/db/drizzle.config.ts'
2026-05-16T09:03:49.2560071Z 8 tables
2026-05-16T09:03:49.2560531Z accounts 8 columns 1 indexes 0 fks
2026-05-16T09:03:49.2560974Z audit_log 6 columns 0 indexes 2 fks
2026-05-16T09:03:49.2561402Z characters 9 columns 0 indexes 1 fks
2026-05-16T09:03:49.2561994Z inventory_items 4 columns 0 indexes 1 fks
2026-05-16T09:03:49.2563002Z legacy_credentials_staging 6 columns 0 indexes 0 fks
2026-05-16T09:03:49.2563516Z message_board_replies 5 columns 0 indexes 2 fks
2026-05-16T09:03:49.2564040Z message_board_topics 7 columns 0 indexes 1 fks
2026-05-16T09:03:49.2564462Z sessions 5 columns 0 indexes 1 fks
2026-05-16T09:03:49.2564669Z 
2026-05-16T09:03:49.2565195Z No schema changes, nothing to migrate 😴
2026-05-16T09:03:49.7059360Z 
2026-05-16T09:03:49.7060217Z === Drizzle: schema-sync ===
2026-05-16T09:03:49.7061051Z >>> pnpm lint:schema-sync
2026-05-16T09:03:49.9311669Z 
2026-05-16T09:03:49.9312812Z > rebno@0.0.0 lint:schema-sync /home/runner/work/rebno/rebno
2026-05-16T09:03:49.9315427Z > node -e "const a=require('fs').readFileSync('packages/db/migrations/0001_baseline.sql');const b=require('fs').readFileSync('docs/extracted-server/0001_baseline.sql');if(Buffer.compare(a,b)!==0){console.error('docs/extracted-server/0001_baseline.sql out of sync with packages/db/migrations/0001_baseline.sql');process.exit(1)}console.log('OK')"
2026-05-16T09:03:49.9317315Z 
2026-05-16T09:03:49.9542597Z OK
2026-05-16T09:03:49.9656723Z 
2026-05-16T09:03:49.9657238Z === Drizzle: source-comments ===
2026-05-16T09:03:49.9657887Z >>> pnpm lint:source-comments
2026-05-16T09:03:50.1909728Z 
2026-05-16T09:03:50.1910885Z > rebno@0.0.0 lint:source-comments /home/runner/work/rebno/rebno
2026-05-16T09:03:50.1912058Z > pnpm -C packages/db run lint:source-comments
2026-05-16T09:03:50.1912513Z 
2026-05-16T09:03:50.4176145Z 
2026-05-16T09:03:50.4177328Z > @rebno/db@0.1.0 lint:source-comments /home/runner/work/rebno/rebno/packages/db
2026-05-16T09:03:50.4178484Z > node scripts/check-source-comments.mjs
2026-05-16T09:03:50.4179008Z 
2026-05-16T09:03:50.4456327Z check-source-comments: OK (50 columns, all SOURCE-cited)
2026-05-16T09:03:50.4637169Z 
2026-05-16T09:03:50.4637699Z === Workspace: test ===
2026-05-16T09:03:50.4638156Z >>> pnpm -r test
2026-05-16T09:03:50.6918430Z Scope: 5 of 6 workspace projects
2026-05-16T09:03:50.6959567Z packages/db test$ vitest run
2026-05-16T09:03:50.6966210Z packages/game-logic test$ vitest run
2026-05-16T09:03:51.0814100Z packages/db test: [1m[30m[46m RUN [49m[39m[22m [36mv4.1.5 [39m[90m/home/runner/work/rebno/rebno/packages/db[39m
2026-05-16T09:03:51.0830251Z packages/game-logic test: [1m[30m[46m RUN [49m[39m[22m [36mv4.1.5 [39m[90m/home/runner/work/rebno/rebno/packages/game-logic[39m
2026-05-16T09:03:51.4257775Z packages/game-logic test:  [32m✓[39m test/step-bno-fidelity.test.ts [2m([22m[2m13 tests[22m[2m)[22m[32m 11[2mms[22m[39m
2026-05-16T09:03:51.5908098Z packages/game-logic test:  [32m✓[39m test/collision-axis-slide.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:03:51.7587860Z packages/game-logic test:  [32m✓[39m test/wall-slide.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:03:51.8524297Z packages/db test:  [32m✓[39m tests/promotion.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 7[2mms[22m[39m
2026-05-16T09:03:51.9343898Z packages/game-logic test:  [32m✓[39m test/golden.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 10[2mms[22m[39m
2026-05-16T09:03:52.0284263Z packages/db test:  [32m✓[39m tests/save-format-traceability.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:03:52.1247761Z packages/game-logic test:  [32m✓[39m test/navi-mask-bbox.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:03:52.2731542Z packages/game-logic test:  [32m✓[39m test/walkable-edge.test.ts [2m([22m[2m1 test[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:03:52.4485227Z packages/game-logic test:  [32m✓[39m test/movement-constants.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:03:52.6164050Z packages/game-logic test:  [32m✓[39m test/sprite-state-machine.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:03:52.6454031Z packages/db test:  [32m✓[39m tests/schema-shape.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 8[2mms[22m[39m
2026-05-16T09:03:52.6461131Z packages/db test: [2m Test Files [22m [1m[32m3 passed[39m[22m[90m (3)[39m
2026-05-16T09:03:52.6472498Z packages/db test: [2m      Tests [22m [1m[32m22 passed[39m[22m[90m (22)[39m
2026-05-16T09:03:52.6492500Z packages/db test: [2m   Start at [22m 09:03:51
2026-05-16T09:03:52.6512873Z packages/db test: [2m   Duration [22m 1.55s[2m (transform 112ms, setup 0ms, import 1.05s, tests 20ms, environment 0ms)[22m
2026-05-16T09:03:52.6607828Z packages/db test: Done
2026-05-16T09:03:52.6608445Z packages/protocol test$ vitest run
2026-05-16T09:03:52.7983904Z packages/game-logic test:  [32m✓[39m test/platform-cycle.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 13[2mms[22m[39m
2026-05-16T09:03:52.9718744Z packages/game-logic test:  [32m✓[39m test/accumulator.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:03:53.0424382Z packages/protocol test: [1m[30m[46m RUN [49m[39m[22m [36mv4.1.5 [39m[90m/home/runner/work/rebno/rebno/packages/protocol[39m
2026-05-16T09:03:53.1517293Z packages/game-logic test:  [32m✓[39m test/run-speed.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:03:53.3022639Z packages/game-logic test:  [32m✓[39m test/rng.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:03:53.3025344Z packages/game-logic test: [2m Test Files [22m [1m[32m12 passed[39m[22m[90m (12)[39m
2026-05-16T09:03:53.3026169Z packages/game-logic test: [2m      Tests [22m [1m[32m61 passed[39m[22m[90m (61)[39m
2026-05-16T09:03:53.3026831Z packages/game-logic test: [2m   Start at [22m 09:03:51
2026-05-16T09:03:53.3027787Z packages/game-logic test: [2m   Duration [22m 2.21s[2m (transform 202ms, setup 0ms, import 370ms, tests 78ms, environment 1ms)[22m
2026-05-16T09:03:53.3596028Z packages/game-logic test: Done
2026-05-16T09:03:53.3631665Z packages/protocol test:  [32m✓[39m test/intents.test.ts [2m([22m[2m15 tests[22m[2m)[22m[32m 12[2mms[22m[39m
2026-05-16T09:03:53.5142871Z packages/protocol test:  [32m✓[39m test/codec.test.ts [2m([22m[2m18 tests[22m[2m)[22m[32m 11[2mms[22m[39m
2026-05-16T09:03:53.6504962Z packages/protocol test:  [32m✓[39m test/state.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:03:53.7682676Z packages/protocol test:  [32m✓[39m test/schema-shape.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:03:53.7718352Z packages/protocol test: [2m Test Files [22m [1m[32m4 passed[39m[22m[90m (4)[39m
2026-05-16T09:03:53.7734502Z packages/protocol test: [2m      Tests [22m [1m[32m41 passed[39m[22m[90m (41)[39m
2026-05-16T09:03:53.7737783Z packages/protocol test: [2m   Start at [22m 09:03:53
2026-05-16T09:03:53.7739073Z packages/protocol test: [2m   Duration [22m 742ms[2m (transform 123ms, setup 0ms, import 222ms, tests 32ms, environment 0ms)[22m
2026-05-16T09:03:53.8090880Z packages/protocol test: Done
2026-05-16T09:03:53.8095355Z apps/client test$ vitest run --exclude 'test/e2e/**'
2026-05-16T09:03:53.8097370Z apps/server test$ vitest run --exclude 'test/**/*.integ.test.ts'
2026-05-16T09:03:54.2054159Z apps/server test: [1m[30m[46m RUN [49m[39m[22m [36mv4.1.5 [39m[90m/home/runner/work/rebno/rebno/apps/server[39m
2026-05-16T09:03:54.2765572Z apps/client test: [1m[46m RUN [49m[22m [36mv3.2.4 [39m[90m/home/runner/work/rebno/rebno/apps/client[39m
2026-05-16T09:03:55.2257969Z apps/server test:  [32m✓[39m test/persistence.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 148[2mms[22m[39m
2026-05-16T09:03:55.3373835Z apps/client test:  [32m✓[39m src/__test__/nameplate-stability.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 38[2mms[22m[39m
2026-05-16T09:03:55.5803916Z apps/server test:  [32m✓[39m test/layout-derive.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 100[2mms[22m[39m
2026-05-16T09:03:55.7798053Z apps/server test:  [32m✓[39m test/rate-limit.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 7[2mms[22m[39m
2026-05-16T09:03:55.9666218Z apps/server test:  [32m✓[39m test/room-key.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 17[2mms[22m[39m
2026-05-16T09:03:56.1957195Z apps/server test: {"level":40,"time":1778922236185,"pid":3241,"hostname":"runnervmrw5os","path":"/api/foo","msg":"staging_invite_rejected"}
2026-05-16T09:03:56.2083755Z apps/server test:  [32m✓[39m test/staging-invite.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 26[2mms[22m[39m
2026-05-16T09:03:56.2137236Z apps/server test: {"level":40,"time":1778922236195,"pid":3241,"hostname":"runnervmrw5os","path":"/api/foo","msg":"staging_invite_rejected"}
2026-05-16T09:03:56.2173211Z apps/server test: {"level":40,"time":1778922236196,"pid":3241,"hostname":"runnervmrw5os","path":"/api/foo","msg":"staging_invite_rejected"}
2026-05-16T09:03:56.7074414Z apps/client test: [90mstderr[2m | src/__test__/game-scene.test.ts[2m > [22m[2mscenes/GameScene[2m > [22m[2mtest 5: onRoomLayout calls verifyRoomLayout first; render skipped on false
2026-05-16T09:03:56.7105544Z apps/client test: [22m[39mroom_layout signature did not verify — rendering anyway (defense-in-depth; see 06.1-D40-SPIKE.md) mvp-lobby 000
2026-05-16T09:03:56.7978389Z apps/client test:  [32m✓[39m src/__test__/game-scene.test.ts [2m([22m[2m10 tests[22m[2m)[22m[32m 230[2mms[22m[39m
2026-05-16T09:03:56.9709548Z apps/server test: {"level":30,"time":1778922236969,"pid":3252,"hostname":"runnervmrw5os","password":"[Redacted]","session_token":"[Redacted]","msg":"login"}
2026-05-16T09:03:56.9763271Z apps/server test:  [32m✓[39m test/otel-init.test.ts [2m([22m[2m4 tests[22m[2m)[22m[33m 562[2mms[22m[39m
2026-05-16T09:03:56.9764774Z apps/server test:      [33m[2m✓[22m[39m does not throw when OTEL_EXPORTER_OTLP_ENDPOINT is unset [33m 455[2mms[22m[39m
2026-05-16T09:03:57.7136293Z apps/server test: [90mstdout[2m | test/run-migrations.test.ts[2m > [22m[2mrun-migrations.ts (Plan 12)[2m > [22m[2mScenario 1: fresh DB — migrate creates accounts table and records migration row
2026-05-16T09:03:57.7169826Z apps/server test: [22m[39m[run-migrations] opening /tmp/rebno-migrate-test-JqEqWF/rebno.db
2026-05-16T09:03:57.7171533Z apps/server test: [run-migrations] migrationsFolder=/home/runner/work/rebno/rebno/packages/db/migrations
2026-05-16T09:03:57.7190164Z apps/server test: [run-migrations] OK
2026-05-16T09:03:57.7293691Z apps/server test: [90mstdout[2m | test/run-migrations.test.ts[2m > [22m[2mrun-migrations.ts (Plan 12)[2m > [22m[2mScenario 2: pre-bootstrapped DB (Assumption A7) — reconcile seeds row before migrate runs
2026-05-16T09:03:57.7301604Z apps/server test: [22m[39m[run-migrations] opening /tmp/rebno-migrate-test-6CnSpo/rebno.db
2026-05-16T09:03:57.7303017Z apps/server test: [run-migrations] migrationsFolder=/home/runner/work/rebno/rebno/packages/db/migrations
2026-05-16T09:03:57.7305061Z apps/server test: [run-migrations] reconciled __drizzle_migrations for pre-bootstrap DB (Assumption A7) — seeded 0001_baseline
2026-05-16T09:03:57.7306316Z apps/server test: [run-migrations] OK
2026-05-16T09:03:57.7343381Z apps/client test:  [31m❯[39m src/__test__/sprite-state-machine.teleport-gate.test.ts [2m([22m[2m3 tests[22m[2m | [22m[31m3 failed[39m[2m)[22m[32m 32[2mms[22m[39m
2026-05-16T09:03:57.7346350Z apps/client test: [31m   [31m×[31m D-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot[2m > [22mTest 1: initial-snapshot batch (before microtask flip) → addRemote called with { playTeleportIn: false } for both pre-existing remotes[39m[32m 23[2mms[22m[39m
2026-05-16T09:03:57.7348796Z apps/client test: [31m     → [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?
2026-05-16T09:03:57.7384141Z apps/client test: If you need to partially mock a module, you can use "importOriginal" helper inside:
2026-05-16T09:03:57.7384961Z apps/client test: [39m
2026-05-16T09:03:57.7387038Z apps/client test: [31m   [31m×[31m D-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot[2m > [22mTest 2: post-microtask remote-add → addRemote called with { playTeleportIn: true } (fresh join during session)[39m[32m 5[2mms[22m[39m
2026-05-16T09:03:57.7389512Z apps/client test: [31m     → [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?
2026-05-16T09:03:57.7391215Z apps/client test: If you need to partially mock a module, you can use "importOriginal" helper inside:
2026-05-16T09:03:57.7392298Z apps/client test: [39m
2026-05-16T09:03:57.7394075Z apps/client test: [31m   [31m×[31m D-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot[2m > [22mTest 3 (negative): self-spawn (onLocalJoin) path is UNCHANGED — does not consult inInitialSnapshot[39m[32m 3[2mms[22m[39m
2026-05-16T09:03:57.7396490Z apps/client test: [31m     → [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?
2026-05-16T09:03:57.7397954Z apps/client test: If you need to partially mock a module, you can use "importOriginal" helper inside:
2026-05-16T09:03:57.7398931Z apps/client test: [39m
2026-05-16T09:03:57.7400541Z apps/server test: [90mstdout[2m | test/run-migrations.test.ts[2m > [22m[2mrun-migrations.ts (Plan 12)[2m > [22m[2mScenario 3: idempotent second run — no error, no extra rows
2026-05-16T09:03:57.7402416Z apps/server test: [22m[39m[run-migrations] opening /tmp/rebno-migrate-test-KpdTw3/rebno.db
2026-05-16T09:03:57.7403555Z apps/server test: [run-migrations] migrationsFolder=/home/runner/work/rebno/rebno/packages/db/migrations
2026-05-16T09:03:57.7404470Z apps/server test: [run-migrations] OK
2026-05-16T09:03:57.7406018Z apps/server test: [90mstdout[2m | test/run-migrations.test.ts[2m > [22m[2mrun-migrations.ts (Plan 12)[2m > [22m[2mScenario 3: idempotent second run — no error, no extra rows
2026-05-16T09:03:57.7407625Z apps/server test: [22m[39m[run-migrations] opening /tmp/rebno-migrate-test-KpdTw3/rebno.db
2026-05-16T09:03:57.7408760Z apps/server test: [run-migrations] migrationsFolder=/home/runner/work/rebno/rebno/packages/db/migrations
2026-05-16T09:03:57.7420555Z apps/server test: [run-migrations] OK
2026-05-16T09:03:57.7466796Z apps/server test:  [32m✓[39m test/run-migrations.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 58[2mms[22m[39m
2026-05-16T09:03:57.9761491Z apps/server test:  [32m✓[39m test/log.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 16[2mms[22m[39m
2026-05-16T09:03:58.1488945Z apps/server test:  [32m✓[39m test/admin-stubs.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:03:58.3852959Z apps/server test:  [32m✓[39m test/legacy-login.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 17[2mms[22m[39m
2026-05-16T09:03:58.5780381Z apps/server test:  [32m✓[39m test/health.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:03:58.6276584Z apps/client test:  [32m✓[39m src/__test__/nameplate.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 45[2mms[22m[39m
2026-05-16T09:03:59.2489529Z apps/server test: [90mstdout[2m | test/tick-accumulator.test.ts
2026-05-16T09:03:59.2504065Z apps/server test: [22m[39m◇ injected env (50) from ../../../../../../../etc/environment // tip: ◈ secrets for agents [www.dotenvx.com]
2026-05-16T09:03:59.2520675Z apps/server test: ℹ️  optional .env file not found: .env.test, .env
2026-05-16T09:03:59.5477378Z apps/client test:  [32m✓[39m src/__test__/colyseus-client.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 13[2mms[22m[39m
2026-05-16T09:03:59.8014757Z apps/server test:  [32m✓[39m test/tick-accumulator.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:03:59.8223412Z apps/server test: [2m Test Files [22m [1m[32m12 passed[39m[22m[90m (12)[39m
2026-05-16T09:03:59.8263604Z apps/server test: [2m      Tests [22m [1m[32m72 passed[39m[22m[90m (72)[39m
2026-05-16T09:03:59.8293370Z apps/server test: [2m   Start at [22m 09:03:54
2026-05-16T09:03:59.8295941Z apps/server test: [2m   Duration [22m 5.60s[2m (transform 451ms, setup 0ms, import 2.63s, tests 967ms, environment 1ms)[22m
2026-05-16T09:03:59.8647021Z apps/server test: Done
2026-05-16T09:04:00.2031351Z apps/client test:  [32m✓[39m src/__test__/sprite-state-machine.test.ts [2m([22m[2m29 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:04:00.7485754Z apps/client test:  [32m✓[39m src/__test__/login-scene.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 9[2mms[22m[39m
2026-05-16T09:04:01.4002212Z apps/client test:  [32m✓[39m src/__test__/reconnect.test.ts [2m([22m[2m16 tests[22m[2m)[22m[32m 56[2mms[22m[39m
2026-05-16T09:04:01.9317936Z apps/client test:  [32m✓[39m src/__test__/player-renderer.teleport.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 11[2mms[22m[39m
2026-05-16T09:04:02.4779874Z apps/client test:  [32m✓[39m src/__test__/player-renderer-spawn-delay.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 15[2mms[22m[39m
2026-05-16T09:04:03.0142584Z apps/client test:  [32m✓[39m src/__test__/input-dispatcher.test.ts [2m([22m[2m12 tests[22m[2m)[22m[32m 12[2mms[22m[39m
2026-05-16T09:04:03.6056963Z apps/client test:  [32m✓[39m src/__test__/chat-hud.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 64[2mms[22m[39m
2026-05-16T09:04:04.1488891Z apps/client test:  [32m✓[39m src/__test__/nameplate-color.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 24[2mms[22m[39m
2026-05-16T09:04:04.7242763Z apps/client test: [90mstderr[2m | src/__test__/background-renderer.test.ts[2m > [22m[2mBackgroundRenderer — wrap math (sim-tick pure state)[2m > [22m[2mD-64 round-4: dispose() survives a group whose .clear() throws (scene-shutdown race)
2026-05-16T09:04:04.7245761Z apps/client test: [22m[39mBackgroundRenderer.dispose: group.clear threw (likely scene-shutdown race) Cannot read properties of undefined (reading 'size')
2026-05-16T09:04:04.7252316Z apps/client test:  [32m✓[39m src/__test__/background-renderer.test.ts [2m([22m[2m9 tests[22m[2m)[22m[32m 59[2mms[22m[39m
2026-05-16T09:04:05.2679999Z apps/client test:  [32m✓[39m src/__test__/reconciler.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:04:05.7769974Z apps/client test:  [32m✓[39m src/__test__/room-renderer.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:04:06.3419971Z apps/client test:  [32m✓[39m src/__test__/force-reset-overlay.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 60[2mms[22m[39m
2026-05-16T09:04:06.9110268Z apps/client test:  [32m✓[39m src/__test__/esc-menu.test.ts [2m([22m[2m8 tests[22m[2m)[22m[32m 61[2mms[22m[39m
2026-05-16T09:04:07.4336790Z apps/client test:  [32m✓[39m src/__test__/prediction.test.ts [2m([22m[2m6 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:04:07.9622776Z apps/client test:  [32m✓[39m src/__test__/extrapolation.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:04:08.4783934Z apps/client test:  [32m✓[39m src/__test__/sprite-state-rate.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 3[2mms[22m[39m
2026-05-16T09:04:08.9911665Z apps/client test:  [32m✓[39m src/__test__/room-layout-verify.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 10[2mms[22m[39m
2026-05-16T09:04:09.4994381Z apps/client test:  [32m✓[39m src/__test__/input-dispatcher-shift.test.ts [2m([22m[2m3 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:04:10.0126098Z apps/client test:  [32m✓[39m src/__test__/boot-font-gate.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:04:10.5560824Z apps/client test:  [32m✓[39m src/__test__/legacy-origin.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:04:11.1345192Z apps/client test:  [32m✓[39m src/__test__/auth-client.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 5[2mms[22m[39m
2026-05-16T09:04:11.6642003Z apps/client test:  [32m✓[39m src/__test__/room-collision-bottom-edge.test.ts [2m([22m[2m5 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:04:12.1926716Z apps/client test:  [32m✓[39m src/__test__/depth-set.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 3[2mms[22m[39m
2026-05-16T09:04:12.7216187Z apps/client test:  [32m✓[39m src/__test__/atlas-loader.test.ts [2m([22m[2m4 tests[22m[2m)[22m[32m 6[2mms[22m[39m
2026-05-16T09:04:13.2408876Z apps/client test:  [32m✓[39m src/__test__/protocol-version-check.test.ts [2m([22m[2m7 tests[22m[2m)[22m[32m 4[2mms[22m[39m
2026-05-16T09:04:13.7589431Z apps/client test:  [32m✓[39m src/__test__/env.test.ts [2m([22m[2m5 tests[22m[2m | [22m[33m4 skipped[39m[2m)[22m[32m 3[2mms[22m[39m
2026-05-16T09:04:13.7778992Z apps/client test: [31m⎯⎯⎯⎯⎯⎯⎯[39m[1m[41m Failed Tests 3 [49m[22m[31m⎯⎯⎯⎯⎯⎯⎯[39m
2026-05-16T09:04:13.7804902Z apps/client test: [41m[1m FAIL [22m[49m src/__test__/sprite-state-machine.teleport-gate.test.ts[2m > [22mD-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot[2m > [22mTest 1: initial-snapshot batch (before microtask flip) → addRemote called with { playTeleportIn: false } for both pre-existing remotes
2026-05-16T09:04:13.7813318Z apps/client test: [31m[1mError[22m: [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?
2026-05-16T09:04:13.7822747Z apps/client test: If you need to partially mock a module, you can use "importOriginal" helper inside:
2026-05-16T09:04:13.7842347Z apps/client test: [39m
2026-05-16T09:04:13.7863108Z apps/client test: vi[33m.[39m[34mmock[39m([35mimport[39m([32m"../net/colyseus-client.js"[39m)[33m,[39m [35masync[39m (importOriginal) [33m=>[39m {
2026-05-16T09:04:13.7864361Z apps/client test:   [35mconst[39m actual [33m=[39m [35mawait[39m [34mimportOriginal[39m()
2026-05-16T09:04:13.7865056Z apps/client test:   [35mreturn[39m {
2026-05-16T09:04:13.7865597Z apps/client test:     [33m...[39mactual[33m,[39m
2026-05-16T09:04:13.7866192Z apps/client test:     [90m// your mocked methods[39m
2026-05-16T09:04:13.7866983Z apps/client test:   }
2026-05-16T09:04:13.7867290Z apps/client test: })
2026-05-16T09:04:13.7868199Z apps/client test: [36m [2m❯[22m GameScene.hasCachedReconnectionToken src/scenes/GameScene.ts:[2m869:43[22m[39m
2026-05-16T09:04:13.8093046Z apps/client test:     [90m867| [39m  [35mprivate[39m [34mhasCachedReconnectionToken[39m()[33m:[39m boolean {
2026-05-16T09:04:13.8113351Z apps/client test:     [90m868| [39m    [35mif[39m ([35mtypeof[39m sessionStorage [33m===[39m [32m'undefined'[39m) [35mreturn[39m [35mfalse[39m[33m;[39m
2026-05-16T09:04:13.8163139Z apps/client test:     [90m869| [39m    [35mreturn[39m [33mBoolean[39m(sessionStorage[33m.[39m[34mgetItem[39m([33mRECONNECT_TOKEN_KEY[39m))[33m;[39m
2026-05-16T09:04:13.8182661Z apps/client test:     [90m   | [39m                                          [31m^[39m
2026-05-16T09:04:13.8222523Z apps/client test:     [90m870| [39m  }
2026-05-16T09:04:13.8240090Z apps/client test:     [90m871| [39m
2026-05-16T09:04:13.8240976Z apps/client test: [90m [2m❯[22m GameScene.create src/scenes/GameScene.ts:[2m217:28[22m[39m
2026-05-16T09:04:13.8242346Z apps/client test: [90m [2m❯[22m bootSceneAndCaptureCallbacks src/__test__/sprite-state-machine.teleport-gate.test.ts:[2m283:17[22m[39m
2026-05-16T09:04:13.8243643Z apps/client test: [90m [2m❯[22m src/__test__/sprite-state-machine.teleport-gate.test.ts:[2m294:41[22m[39m
2026-05-16T09:04:13.8244547Z apps/client test: [31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/3]⎯[22m[39m
2026-05-16T09:04:13.8246724Z apps/client test: [41m[1m FAIL [22m[49m src/__test__/sprite-state-machine.teleport-gate.test.ts[2m > [22mD-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot[2m > [22mTest 2: post-microtask remote-add → addRemote called with { playTeleportIn: true } (fresh join during session)
2026-05-16T09:04:13.8249035Z apps/client test: [31m[1mError[22m: [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?
2026-05-16T09:04:13.8250287Z apps/client test: If you need to partially mock a module, you can use "importOriginal" helper inside:
2026-05-16T09:04:13.8250970Z apps/client test: [39m
2026-05-16T09:04:13.8252251Z apps/client test: vi[33m.[39m[34mmock[39m([35mimport[39m([32m"../net/colyseus-client.js"[39m)[33m,[39m [35masync[39m (importOriginal) [33m=>[39m {
2026-05-16T09:04:13.8253392Z apps/client test:   [35mconst[39m actual [33m=[39m [35mawait[39m [34mimportOriginal[39m()
2026-05-16T09:04:13.8254058Z apps/client test:   [35mreturn[39m {
2026-05-16T09:04:13.8254609Z apps/client test:     [33m...[39mactual[33m,[39m
2026-05-16T09:04:13.8255206Z apps/client test:     [90m// your mocked methods[39m
2026-05-16T09:04:13.8255633Z apps/client test:   }
2026-05-16T09:04:13.8255941Z apps/client test: })
2026-05-16T09:04:13.8256831Z apps/client test: [36m [2m❯[22m GameScene.hasCachedReconnectionToken src/scenes/GameScene.ts:[2m869:43[22m[39m
2026-05-16T09:04:13.8258110Z apps/client test:     [90m867| [39m  [35mprivate[39m [34mhasCachedReconnectionToken[39m()[33m:[39m boolean {
2026-05-16T09:04:13.8259557Z apps/client test:     [90m868| [39m    [35mif[39m ([35mtypeof[39m sessionStorage [33m===[39m [32m'undefined'[39m) [35mreturn[39m [35mfalse[39m[33m;[39m
2026-05-16T09:04:13.8261172Z apps/client test:     [90m869| [39m    [35mreturn[39m [33mBoolean[39m(sessionStorage[33m.[39m[34mgetItem[39m([33mRECONNECT_TOKEN_KEY[39m))[33m;[39m
2026-05-16T09:04:13.8263935Z apps/client test:     [90m   | [39m                                          [31m^[39m
2026-05-16T09:04:13.8264541Z apps/client test:     [90m870| [39m  }
2026-05-16T09:04:13.8264998Z apps/client test:     [90m871| [39m
2026-05-16T09:04:13.8266941Z apps/client test: [90m [2m❯[22m GameScene.create src/scenes/GameScene.ts:[2m217:28[22m[39m
2026-05-16T09:04:13.8268194Z apps/client test: [90m [2m❯[22m bootSceneAndCaptureCallbacks src/__test__/sprite-state-machine.teleport-gate.test.ts:[2m283:17[22m[39m
2026-05-16T09:04:13.8269893Z apps/client test: [90m [2m❯[22m src/__test__/sprite-state-machine.teleport-gate.test.ts:[2m328:41[22m[39m
2026-05-16T09:04:13.8271020Z apps/client test: [31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/3]⎯[22m[39m
2026-05-16T09:04:13.8273309Z apps/client test: [41m[1m FAIL [22m[49m src/__test__/sprite-state-machine.teleport-gate.test.ts[2m > [22mD-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot[2m > [22mTest 3 (negative): self-spawn (onLocalJoin) path is UNCHANGED — does not consult inInitialSnapshot
2026-05-16T09:04:13.8275673Z apps/client test: [31m[1mError[22m: [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?
2026-05-16T09:04:13.8276963Z apps/client test: If you need to partially mock a module, you can use "importOriginal" helper inside:
2026-05-16T09:04:13.8277626Z apps/client test: [39m
2026-05-16T09:04:13.8278729Z apps/client test: vi[33m.[39m[34mmock[39m([35mimport[39m([32m"../net/colyseus-client.js"[39m)[33m,[39m [35masync[39m (importOriginal) [33m=>[39m {
2026-05-16T09:04:13.8279972Z apps/client test:   [35mconst[39m actual [33m=[39m [35mawait[39m [34mimportOriginal[39m()
2026-05-16T09:04:13.8280668Z apps/client test:   [35mreturn[39m {
2026-05-16T09:04:13.8281221Z apps/client test:     [33m...[39mactual[33m,[39m
2026-05-16T09:04:13.8312212Z apps/client test:     [90m// your mocked methods[39m
2026-05-16T09:04:13.8312717Z apps/client test:   }
2026-05-16T09:04:13.8313048Z apps/client test: })
2026-05-16T09:04:13.8314033Z apps/client test: [36m [2m❯[22m GameScene.hasCachedReconnectionToken src/scenes/GameScene.ts:[2m869:43[22m[39m
2026-05-16T09:04:13.8315316Z apps/client test:     [90m867| [39m  [35mprivate[39m [34mhasCachedReconnectionToken[39m()[33m:[39m boolean {
2026-05-16T09:04:13.8316742Z apps/client test:     [90m868| [39m    [35mif[39m ([35mtypeof[39m sessionStorage [33m===[39m [32m'undefined'[39m) [35mreturn[39m [35mfalse[39m[33m;[39m
2026-05-16T09:04:13.8318277Z apps/client test:     [90m869| [39m    [35mreturn[39m [33mBoolean[39m(sessionStorage[33m.[39m[34mgetItem[39m([33mRECONNECT_TOKEN_KEY[39m))[33m;[39m
2026-05-16T09:04:13.8319338Z apps/client test:     [90m   | [39m                                          [31m^[39m
2026-05-16T09:04:13.8319904Z apps/client test:     [90m870| [39m  }
2026-05-16T09:04:13.8320327Z apps/client test:     [90m871| [39m
2026-05-16T09:04:13.8321061Z apps/client test: [90m [2m❯[22m GameScene.create src/scenes/GameScene.ts:[2m217:28[22m[39m
2026-05-16T09:04:13.8322639Z apps/client test: [90m [2m❯[22m bootSceneAndCaptureCallbacks src/__test__/sprite-state-machine.teleport-gate.test.ts:[2m283:17[22m[39m
2026-05-16T09:04:13.8323991Z apps/client test: [90m [2m❯[22m src/__test__/sprite-state-machine.teleport-gate.test.ts:[2m362:41[22m[39m
2026-05-16T09:04:13.8324869Z apps/client test: [31m[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/3]⎯[22m[39m
2026-05-16T09:04:13.8325837Z apps/client test: [2m Test Files [22m [1m[31m1 failed[39m[22m[2m | [22m[1m[32m30 passed[39m[22m[90m (31)[39m
2026-05-16T09:04:13.8337494Z apps/client test: [2m      Tests [22m [1m[31m3 failed[39m[22m[2m | [22m[1m[32m220 passed[39m[22m[2m | [22m[90m4 todo[39m[90m (227)[39m
2026-05-16T09:04:13.8338452Z apps/client test: [2m   Start at [22m 09:03:54
2026-05-16T09:04:13.8339661Z apps/client test: [2m   Duration [22m 19.50s[2m (transform 679ms, setup 45ms, collect 1.36s, tests 805ms, environment 11.28s, prepare 2.12s)[22m
2026-05-16T09:04:13.8363026Z apps/client test: ::error file=/home/runner/work/rebno/rebno/apps/client/src/scenes/GameScene.ts,title=src/__test__/sprite-state-machine.teleport-gate.test.ts > D-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot > Test 1%3A initial-snapshot batch (before microtask flip) → addRemote called with { playTeleportIn%3A false } for both pre-existing remotes,line=869,column=43::Error: [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?%0AIf you need to partially mock a module, you can use "importOriginal" helper inside:%0A%0Avi.mock(import("../net/colyseus-client.js"), async (importOriginal) => {%0A  const actual = await importOriginal()%0A  return {%0A    ...actual,%0A    // your mocked methods%0A  }%0A})%0A%0A ❯ GameScene.hasCachedReconnectionToken src/scenes/GameScene.ts:869:43%0A ❯ GameScene.create src/scenes/GameScene.ts:217:28%0A ❯ bootSceneAndCaptureCallbacks src/__test__/sprite-state-machine.teleport-gate.test.ts:283:17%0A ❯ src/__test__/sprite-state-machine.teleport-gate.test.ts:294:41%0A%0A
2026-05-16T09:04:13.8378968Z apps/client test: ::error file=/home/runner/work/rebno/rebno/apps/client/src/scenes/GameScene.ts,title=src/__test__/sprite-state-machine.teleport-gate.test.ts > D-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot > Test 2%3A post-microtask remote-add → addRemote called with { playTeleportIn%3A true } (fresh join during session),line=869,column=43::Error: [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?%0AIf you need to partially mock a module, you can use "importOriginal" helper inside:%0A%0Avi.mock(import("../net/colyseus-client.js"), async (importOriginal) => {%0A  const actual = await importOriginal()%0A  return {%0A    ...actual,%0A    // your mocked methods%0A  }%0A})%0A%0A ❯ GameScene.hasCachedReconnectionToken src/scenes/GameScene.ts:869:43%0A ❯ GameScene.create src/scenes/GameScene.ts:217:28%0A ❯ bootSceneAndCaptureCallbacks src/__test__/sprite-state-machine.teleport-gate.test.ts:283:17%0A ❯ src/__test__/sprite-state-machine.teleport-gate.test.ts:328:41%0A%0A
2026-05-16T09:04:13.8391372Z apps/client test: ::error file=/home/runner/work/rebno/rebno/apps/client/src/scenes/GameScene.ts,title=src/__test__/sprite-state-machine.teleport-gate.test.ts > D-55d initial-snapshot TeleIn gate — GameScene.inInitialSnapshot > Test 3 (negative)%3A self-spawn (onLocalJoin) path is UNCHANGED — does not consult inInitialSnapshot,line=869,column=43::Error: [vitest] No "RECONNECT_TOKEN_KEY" export is defined on the "../net/colyseus-client.js" mock. Did you forget to return it from "vi.mock"?%0AIf you need to partially mock a module, you can use "importOriginal" helper inside:%0A%0Avi.mock(import("../net/colyseus-client.js"), async (importOriginal) => {%0A  const actual = await importOriginal()%0A  return {%0A    ...actual,%0A    // your mocked methods%0A  }%0A})%0A%0A ❯ GameScene.hasCachedReconnectionToken src/scenes/GameScene.ts:869:43%0A ❯ GameScene.create src/scenes/GameScene.ts:217:28%0A ❯ bootSceneAndCaptureCallbacks src/__test__/sprite-state-machine.teleport-gate.test.ts:283:17%0A ❯ src/__test__/sprite-state-machine.teleport-gate.test.ts:362:41%0A%0A
2026-05-16T09:04:13.9204314Z apps/client test: Failed
2026-05-16T09:04:13.9312778Z /home/runner/work/rebno/rebno/apps/client:
2026-05-16T09:04:13.9314381Z  ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL  @rebno/client@0.1.0 test: `vitest run --exclude 'test/e2e/**'`
2026-05-16T09:04:13.9315069Z Exit status 1
2026-05-16T09:04:13.9486796Z 
2026-05-16T09:04:13.9487480Z verify-phase-4 FAILED at step 'Workspace: test': pnpm -r test (exit 1)
2026-05-16T09:04:13.9492682Z Fix the failing step and re-run `pnpm verify:phase-4`.
2026-05-16T09:04:13.9632192Z  ELIFECYCLE  Command failed with exit code 1.
2026-05-16T09:04:13.9811070Z ##[error]Process completed with exit code 1.
